/*
 *  move.c
 *
 *  Created on: 2010-5-12
 *      Author: liuyond
 *    Abstract: this file will implement the simulation of the following instruction
 *    			MOV, XCHG, LEA, LDS, LES, CBW, CWD, XLAT
 */
#include "cpu.h"

void MOV_Eb_Gb(cpu_t *cpu, instruction_t *i)
{
	int tmp;

	if (i->operand.mod == 0x3)
	{
		// register operand
		tmp = cpu_get_regb(cpu, i->operand.reg);
		cpu_set_reg(cpu, i->operand.rm, tmp);
	}
	else
	{
		// memory operand
		tmp = cpu_get_regb(cpu, i->operand.reg);
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, tmp);
	}
}

void MOV_Ev_Gv(cpu_t *cpu, instruction_t *i)
{
	int tmp;

	if (i->operand.mod == 0x3)
	{
		// register operand
		tmp = cpu_get_reg(cpu, i->operand.reg);
		cpu_set_reg(cpu, i->operand.rm, tmp);
	}
	else
	{
		// memory operand
		tmp = cpu_get_reg(cpu, i->operand.reg);
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, tmp);
	}
}

void MOV_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	int tmp;

	if (i->operand.mod == 0x3)
	{
		// register operand
		tmp = cpu_get_regb(cpu, i->operand.rm);
		cpu_set_regb(cpu, i->operand.reg, tmp);
	}
	else
	{
		// memory operand
		tmp = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		cpu_set_regb(cpu, i->operand.reg, tmp);
	}
}
void MOV_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	int tmp;

	if (i->operand.mod == 0x3)
	{
		// register operand
		tmp = cpu_get_reg(cpu, i->operand.rm);
		cpu_set_reg(cpu, i->operand.reg, tmp);
	}
	else
	{
		// memory operand
		tmp = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		cpu_set_reg(cpu, i->operand.reg, tmp);
	}
}

void MOV_Ew_Sw(cpu_t *cpu, instruction_t *i)
{
	int tmp;

	if (i->operand.mod == 0x3)
	{
		// register operand
		tmp = cpu_get_seg(cpu, i->operand.reg);
		cpu_set_reg(cpu, i->operand.rm, tmp);
	}
	else
	{
		// memory operand
		tmp = cpu_get_seg(cpu, i->operand.reg);
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, tmp);
	}
}

void MOV_Sw_Ew(cpu_t *cpu, instruction_t *i)
{
	int tmp;

	if (i->operand.mod == 0x3)
	{
		// register operand
		tmp = cpu_get_reg(cpu, i->operand.rm);
		cpu_set_reg(cpu, i->operand.seg, tmp);
	}
	else
	{
		// memory operand
		tmp = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		cpu_set_seg(cpu, i->operand.reg, tmp);
	}
}

void MOV_RL_Ib(cpu_t *cpu, instruction_t *i)
{
	int index = i->opcode & 0x7;
	cpu_set_regb(cpu, index, i->operand.imm);
}

void MOV_RX_Iv(cpu_t *cpu, instruction_t *i)
{
	int index = i->opcode & 0x7;
	cpu_set_reg(cpu, index, i->operand.imm);
}

void MOV_AL_Ob(cpu_t *cpu, instruction_t *i)
{
	cpu_set_regb(cpu, AL, i->operand.imm);
}
void MOV_AX_Ov(cpu_t *cpu, instruction_t *i)
{
	cpu_set_reg(cpu, AX, i->operand.imm);
}

void MOV_Ob_AL(cpu_t *cpu, instruction_t *i)
{
	int tmp = cpu_get_regb(cpu, AL);
	cpu_set_mem_byte(cpu, i->operand.seg, i->operand.imm, tmp);
}

void MOV_Ov_AX(cpu_t *cpu, instruction_t *i)
{
	int tmp = cpu_get_reg(cpu, AX);
	cpu_set_mem_word(cpu, i->operand.seg, i->operand.imm, tmp);
}

void MOV_Eb_Ib(cpu_t *cpu, instruction_t *i)
{
	int tmp = i->operand.imm;

	if (i->operand.mod == 0x3)
	{
		// register operand
		cpu_set_regb(cpu, i->operand.rm, tmp);
	}
	else
	{
		// memory operand
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, tmp);
	}
}

void MOV_Ev_Iv(cpu_t *cpu, instruction_t *i)
{
	int tmp = i->operand.imm;

	if (i->operand.mod == 0x3)
	{
		// register operand
		cpu_set_reg(cpu, i->operand.rm, tmp);
	}
	else
	{
		// memory operand
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, tmp);
	}
}

void XCHG_RX_AX(cpu_t *cpu, instruction_t *i)
{
	int ax, rx;
	int index = i->opcode & 0x7;

	ax = cpu_get_reg(cpu, AX);
	rx = cpu_get_reg(cpu, index);
	cpu_set_reg(cpu, AX, rx);
	cpu_set_reg(cpu, index, ax);
}

void XCHG_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	int src, dst;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, i->operand.reg);
		cpu_set_regb(cpu, i->operand.rm, dst);
		cpu_set_regb(cpu, i->operand.reg, src);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, i->operand.reg);
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, dst);
		cpu_set_regb(cpu, i->operand.reg, src);
	}
}

void XCHG_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	int src, dst;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, i->operand.reg);
		cpu_set_reg(cpu, i->operand.rm, dst);
		cpu_set_reg(cpu, i->operand.reg, src);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, i->operand.reg);
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, dst);
		cpu_set_reg(cpu, i->operand.reg, src);
	}
}


void LEA_Gv_Mv(cpu_t *cpu, instruction_t *i)
{
	int index = i->operand.reg;
	int tmp = i->operand.address;
	cpu_set_reg(cpu, index, tmp);
}

void LDS_Gv_Mp(cpu_t *cpu, instruction_t *i)
{
	int index = i->operand.reg;
	int tmp = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
	cpu_set_reg(cpu, index, tmp);
	tmp = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address+sizeof(word));
	cpu_set_seg(cpu, DS, tmp);
}

void LES_Gv_Mp(cpu_t *cpu, instruction_t *i)
{
	int index = i->operand.reg;
	int tmp = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
	cpu_set_reg(cpu, index, tmp);
	tmp = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address+sizeof(word));
	cpu_set_seg(cpu, ES, tmp);
}

void CBW(cpu_t *cpu, instruction_t *i)
{
	if (cpu_get_regb(cpu, AL) & 0x80)
	{
		cpu_set_regb(cpu, AH, 0xFF);
	}
	else
	{
		cpu_set_regb(cpu, AH, 0);
	}
}

void CWD(cpu_t *cpu, instruction_t *i)
{
	if (cpu_get_regb(cpu, AX) & 0x8000)
	{
		cpu_set_regb(cpu, DX, 0xFFFF);
	}
	else
	{
		cpu_set_regb(cpu, DX, 0);
	}
}

void XLAT(cpu_t *cpu, instruction_t *i)
{
	int tmp = cpu_get_reg(cpu, BX);
	tmp += cpu_get_regb(cpu, AL);
	tmp = cpu_get_mem_byte(cpu, DS, tmp);
	cpu_set_regb(cpu, AL, tmp);
}
